#pragma once
#include "..\Common\TypeBase.h"

template <typename T>
class NAutoPtr
{
protected:
	int* m_Count;
	BOOL* m_Owned;
	T* m_Object;

	void Init()
	{
		m_Object = 0;
		m_Count = 0;
		m_Owned = 0;
	}
public:
	NAutoPtr()
	{
		Init();
	}

	~NAutoPtr()
	{
		Dec();
	}

	void SetObject(T* Object)
	{
		Dec();
		if(Object)
		{
			m_Count = new int(1);
			m_Owned = new BOOL(TRUE);
			m_Object = Object;
		}
		else
		{
			Init();
		}
	}

	void Inc()
	{
		if(m_Count)
			(*m_Count)++;
	}

	void Dec()
	{
		if(m_Count)
		{
			if(--*m_Count == 0)
			{
				if(m_Object)
					delete m_Object;
				delete m_Count;
				delete m_Owned;
				Init();
			}
		}
	}

	operator BOOL()const
	{
		return m_Object != 0;
	}

	template<typename Type>
	NAutoPtr(const NAutoPtr<Type>& Temp)
	{
		T* Casted_Object = dynamic_cast<T*>(Temp.Buffer());
		if(Casted_Object)
		{
			m_Count = Temp.GetCount();
			m_Owned = Temp.GetOwned();
			m_Object = Casted_Object;
			Inc();
		}
		else
		{
			Init();
			SetObject(0);
		}
	}

	NAutoPtr(T* Temp)
	{
		Init();
		SetObject(Temp);
	}

	NAutoPtr(const NAutoPtr<T>& Temp)
	{
		m_Count = Temp.m_Count;
		m_Owned = Temp.m_Owned;
		m_Object = Temp.m_Object;
		Inc();
	}

	NAutoPtr<T>& operator =(T* Obj)
	{
		SetObject(Obj);
		return *this;
	}

	NAutoPtr<T>& operator =(const NAutoPtr<T>& Obj)
	{
		if(this != &Obj)
		{
			Dec();
			m_Object = Obj.m_Object;
			m_Count = Obj.m_Count;
			m_Owned = Obj.m_Owned;
			Inc();
		}
		return *this;
	}

	template <typename Type>
	NAutoPtr<T>& operator =(const NAutoPtr<Type>& Obj)
	{
		T* Casted_Object = dynamic_cast<T*>(Obj.Buffer());
		if(Casted_Object)
		{
			m_Count = Obj.GetCount();
			m_Owned = Obj.GetOwned();
			m_Object = Casted_Object;
			Inc();
		}
		else
		{
			Init();
			SetObject(0);
		}
		return *this;
	}

	BOOL operator ==(T* Obj) const
	{
		return *m_Object == *Obj;
	}

	BOOL operator ==(const NAutoPtr<T>& Obj) const
	{
		return *m_Object == *Obj.m_Object;
	}

	BOOL operator !=(T* Obj) const
	{
		return *m_Object != *Obj;
	}

	BOOL operator !=(const NAutoPtr<T>& Obj) const
	{
		return *m_Object != *Obj.m_Object;
	}

	T* operator ->() const
	{
		return m_Object;
	}

	/*T operator[](int n)
	{
		return (*m_Object)[n];
	}*/

	/*T operator*()
	{
		return *m_Object;
	}*/

	T* Buffer() const
	{
		return m_Object;
	}

	int* GetCount() const
	{
		return m_Count;
	}

	BOOL* GetOwned() const
	{
		return m_Owned;
	}
};
/*
template <typename T>
class NAutoPtr
{
protected:
	int*				counter;
	T*					reference;

	void Inc()
	{
		if(counter)
		{
			(*counter)++;
		}
	}

	void Dec()
	{
		if(counter)
		{
			if(--(*counter)==0)
			{
				delete counter;
				delete reference;
				counter=0;
				reference=0;
			}
		}
	}
public:
	NAutoPtr()
	{
		counter=0;
		reference=0;
	}

	NAutoPtr(T* pointer)
	{
		if(pointer)
		{
			counter=new int(1);
			reference=pointer;
		}
		else
		{
			counter=0;
			reference=0;
		}
	}

	NAutoPtr(const NAutoPtr<T>& pointer)
	{
		counter=pointer.counter;
		reference=pointer.reference;
		Inc();
	}

	template<typename C>
	NAutoPtr(const NAutoPtr<C>& pointer)
	{
		T* converted=dynamic_cast<T*>(pointer.Obj());
		if(converted)
		{
			counter=pointer.Counter();
			reference=converted;
			Inc();
		}
		else
		{
			counter=0;
			reference=0;
		}
	}

	~NAutoPtr()
	{
		Dec();
	}

	NAutoPtr<T>& operator=(T* pointer)
	{
		Dec();
		if(pointer)
		{
			counter=new int(1);
			reference=pointer;
		}
		else
		{
			counter=0;
			reference=0;
		}
		return *this;
	}

	NAutoPtr<T>& operator=(const NAutoPtr<T>& pointer)
	{
		if(this!=&pointer)
		{
			Dec();
			counter=pointer.counter;
			reference=pointer.reference;
			Inc();
		}
		return *this;
	}

	template<typename C>
	NAutoPtr<T>& operator=(const NAutoPtr<C>& pointer)
	{
		T* converted=dynamic_cast<T*>(pointer.Obj());
		Dec();
		if(converted)
		{
			counter=pointer.Counter();
			reference=converted;
			Inc();
		}
		else
		{
			counter=0;
			reference=0;
		}
		return *this;
	}

	bool operator==(const T* pointer)const
	{
		return reference==pointer;
	}

	bool operator!=(const T* pointer)const
	{
		return reference!=pointer;
	}

	bool operator>(const T* pointer)const
	{
		return reference>pointer;
	}

	bool operator>=(const T* pointer)const
	{
		return reference>=pointer;
	}

	bool operator<(const T* pointer)const
	{
		return reference<pointer;
	}

	bool operator<=(const T* pointer)const
	{
		return reference<=pointer;
	}

	bool operator==(const NAutoPtr<T>& pointer)const
	{
		return reference==pointer.reference;
	}

	bool operator!=(const NAutoPtr<T>& pointer)const
	{
		return reference!=pointer.reference;
	}

	bool operator>(const NAutoPtr<T>& pointer)const
	{
		return reference>pointer.reference;
	}

	bool operator>=(const NAutoPtr<T>& pointer)const
	{
		return reference>=pointer.reference;
	}

	bool operator<(const NAutoPtr<T>& pointer)const
	{
		return reference<pointer.reference;
	}

	bool operator<=(const NAutoPtr<T>& pointer)const
	{
		return reference<=pointer.reference;
	}

	operator bool()const
	{
		return reference!=0;
	}

	T* Obj()const
	{
		return reference;
	}

	int* Counter()const
	{
		return counter;
	}

	T* operator->()const
	{
		return reference;
	}
};
*/